package services

import (
	"errors"
	"fmt"
	"longmen/server/config/global"
	_const "longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/common/payment/client"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"strconv"
	"time"

	"github.com/spf13/cast"

	"longmen/server/pkg/common/api_models"
)

func genOrderId() string {
	currTime := strconv.FormatInt(time.Now().UnixMilli(), 36)
	orderId := util.RandomLetterNumString(14-len(currTime)) + currTime + util.RandomLetterNumString(6)
	return orderId
}

func (s *Service) CommitOrder(r *api_models.OrderReq, callbackHost string, uid int) (*api_models.OrderResp, error) {
	r.PayProductType = 2 //金币
	r.PayProductname = "GOLD"
	payChannel := 1 //支付渠道

	prdNum := int(cast.ToFloat64(r.PayProductnum) * 100)
	if prdNum <= 0 {
		return nil, errors.New("商品数量不正确")
	}

	switch r.PayMethod {
	case "WXPAY":
		payChannel = 1
		r.PayBankcode = "901"
	case "ALIPAY":
		payChannel = 2
		r.PayBankcode = "906"
	default:
		return nil, errors.New("支付方式不正确")
	}

	// 克拉 价格1元/个,根据个数反查实际价格
	var results []*struct {
		models_main.GoldPrice
		Total int `json:"total"`
	}
	err := global.GetR().Model(models_main.GoldPrice{}).Select("*, (gold + gold_added) as total").Where("price = ?", prdNum).Scan(&results).Error
	if err != nil {
		return nil, err
	}

	amount := float64(prdNum) / 100.0 //单位为元
	gold := prdNum * 10
	goldAdded := 0
	if len(results) > 0 {
		gold = results[0].Gold
		goldAdded = results[0].GoldAdded
	}

	orderId := genOrderId()
	payAmount := fmt.Sprintf("%.2f", amount)
	result, err := client.LsPay(callbackHost, orderId, r.PayBankcode, payAmount, r.PayProductname, cast.ToString(gold+goldAdded), r.PayProductdesc, r.PayProducturl)
	if err != nil {
		return nil, err
	}

	order := models_main.Order{
		Uid:        uid,
		OrderNo:    orderId,
		Type:       0,
		ApiId:      1,
		Amount:     amount,
		PayAmount:  0,
		PayChannel: payChannel,
		CreateTime: time.Now(),
		UpdateTime: time.Now(),
		Gold:       gold,
		GoldAdded:  goldAdded,
	}
	if err = db_main.InsertOrder(nil, &order); err != nil {
		return nil, err
	}

	resp := api_models.OrderResp{}
	resp.Orderid = orderId
	if r.PayBankcode == "902" || r.PayBankcode == "903" || r.PayBankcode == "908" {
		resp.HtmlStr = result
	} else {
		resp.JumpUrl = result
	}
	return &resp, nil
}

func (s *Service) OrderResultNotify(r *api_models.OrderResultNotifyReq) (string, error) {
	fName := "OrderResultNotify"
	html := "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>接口回调</title></head><body><p>OK</p></body></html>"

	//校验请求信息
	sign := r.Sign
	params := map[string]string{
		"memberid":       r.Memberid,
		"orderid":        r.Orderid,
		"amount":         r.Amount,
		"transaction_id": r.TransactionId,
		"datetime":       r.Datetime,
		"returncode":     r.Returncode,
	}
	if len(r.Attach) > 0 {
		params["attach"] = r.Attach
	}

	newSign, _ := client.LsuSign(params)
	if len(sign) <= 0 || sign != newSign {
		return "验签失败", errors.New("验签失败")
	}

	// 更新订单信息
	order, err := db_main.GetOrderParam(map[string]interface{}{"order_no": r.Orderid})
	if err != nil {
		return "", err
	}
	if order.PayStatus == 1 {
		return html, nil
	}

	status := 3
	if r.Returncode == "00" {
		status = 1
	}
	amount, err := strconv.ParseFloat(r.Amount, 32)
	order.PayAmount = amount
	order.PayStatus = status
	order.OutTradeNo = r.TransactionId
	order.UpdateTime = time.Now()

	key := fmt.Sprintf("OrderResultNotify:%s", r.TransactionId)
	val := global.GetRds().SetNX(key, 1, time.Second*5).Val()
	if !val {
		return "", errors.New("订单正在处理")
	}
	defer global.GetRds().Del(key)

	session := s.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			session.Rollback()
		}
	}()

	if err := session.Error; err != nil {
		return "", fmt.Errorf("%s%s", util.Convert(fName), err.Error())
	}

	err = db_main.UpdateOrder(session, []string{"pay_status", "update_time", "out_trade_no", "pay_amount"}, order)
	if err != nil {
		session.Rollback()
		return "", fmt.Errorf("%s%s", util.Convert(fName), err.Error())
	}

	userProfit := &models_main.UserProfit{
		Uid:         order.Uid,
		CoinCount:   order.Gold + order.GoldAdded,
		Content:     util.GetConsumeName(6),
		Type:        _const.FINANCE_DEBIT,
		ConsumeType: _const.PROFIT_DEPOSIT,
		Resid:       0,
		Count:       1, //数量为1
		CreateTime:  time.Now(),
		CoinType:    _const.FEE_TYPE_GOLD,
		FUid:        0, //没有收款人，所以前台不显示收款人是谁
		OrderNo:     order.OrderNo,
		Liveid:      0,
	}
	_, _, err = db_main.UpdateAmountByTx(order.Uid, userProfit.CoinCount, _const.CoinGold, session, _const.WALLET_BALANCE_HIDE, []*models_main.UserProfit{userProfit})
	if err != nil {
		session.Rollback()
		return "", fmt.Errorf("%s%s", util.Convert(fName), err.Error())
	}

	if err := session.Commit().Error; err != nil {
		session.Rollback()
		return "", fmt.Errorf("%s%s", util.Convert(fName), err.Error())
	}
	return html, nil
}

func (s *Service) QueryOrder(r *api_models.SearchOrderReq) (*api_models.SearchOrderResp, error) {
	result, err := client.LsQuery(r.PayOrderid)
	resp := api_models.SearchOrderResp{}
	if err := util.Json2Struct(result, resp); err != nil {
		return nil, err
	}
	return &resp, err
}

func (s *Service) OrderList(uid int, r *api_models.PageParam) (*api_models.OrderListResp, error) {
	resp := &api_models.OrderListResp{}
	list, err := db_main.GetOrdersParam(map[string]interface{}{"uid": uid}, "create_time desc", r.Page, r.Size)
	count, err := db_main.GetOrderCount(map[string]interface{}{"uid": uid})
	resp.List = list
	resp.TotalCount = count
	return resp, err
}
